package hikari.instruments;

import com.gooddies.wiring.annotations.Wire;
import com.gooddies.wiring.annotations.WiringComponent;
import hikari.gui.panels.BasicObjectPropertiesPanel;
import hikari.gui.panels.ModifyPanel;
import hikari.managers.Manager3D;
import hikari.math.CircleCollider;
import hikari.math.CircleDrawer;
import hikari.utils.Vector;
import org.swig.jirr.ISceneCollisionManager;
import org.swig.jirr.ISceneNode;
import org.swig.jirr.IVideoDriver;
import org.swig.jirr.quaternion;
import org.swig.jirr.vector3df;

/**
 * @author Dmitry
 */
@WiringComponent(singleton = true, lazy = true)
public class RotationInstrument extends AbstractTransformationInstrument {

    private float axisX1, axisY1, axisX2, axisY2;
    private CircleDrawer xdrawer;
    private CircleDrawer ydrawer;
    private CircleDrawer zdrawer;
    private float lastLength;
    @Wire
    private Manager3D manager3D;
    @Wire
    private ModifyPanel modifyPanel;

    private RotationInstrument() {
    }

    @Override
    protected void drawGizmo(ISceneNode node) {
        IVideoDriver driver = manager3D.getVideoDriver();
        vector3df cameraPosition = manager3D.getCamera().getRealCamera().getAbsolutePosition();
        node.updateAbsolutePosition();
        gizmo_position = node.getAbsolutePosition();

        driver.resetTransformMatrix();

        float radius = getGizmoLength(gizmo_position);
        float stepCount = engineProperties.getFloatProperty("rotationGizmoSegmentCount");

        vector3df rotation = node.getRotation();
        vector3df frontVector = rotation.rotationToDirection();
        driver.setMaterial(selectedAxis == 'z' ? selectedColor : zColor);
        zdrawer = new CircleDrawer((int) stepCount, gizmo_position, frontVector, radius);
        zdrawer.drawCircleFrontPart(cameraPosition);

        vector3df upvector = rotation.rotationToDirection(new vector3df(0, 1, 0));
        driver.setMaterial(selectedAxis == 'y' ? selectedColor : yColor);
        ydrawer = new CircleDrawer((int) stepCount, gizmo_position, upvector, radius);
        ydrawer.drawCircleFrontPart(cameraPosition);

        vector3df leftVector = rotation.rotationToDirection(new vector3df(1, 0, 0));
        driver.setMaterial(selectedAxis == 'x' ? selectedColor : xColor);
        xdrawer = new CircleDrawer((int) stepCount, gizmo_position, leftVector, radius);
        xdrawer.drawCircleFrontPart(cameraPosition);
    }

    @Override
    protected void changeObject(ISceneNode node, char axis, float length) {
        vector3df rotation = null;
        switch (axis) {
            case 'y':
                rotation = vector3df.DIR_UP;
                break;
            case 'x':
                rotation = vector3df.DIR_RIGHT;
                break;
            case 'z':
                rotation = vector3df.DIR_FRONT;
                break;
        }

        testRotateInLocalSpace(node, length, rotation);
        manager3D.render();
        modifyPanel.updateTransformationData(BasicObjectPropertiesPanel.UPDATE_TYPE.ROTATE);
    }
    float angle = 0.004f;

    @Override
    public void mouseMove(int x, int y, int dx, int dy, int modifier) {
        if (dragAxis) {
            Vector mouseMove = new Vector(dx, dy);
            Vector projection = mouseMove.getVectorProjection(axisDirection);
            float length = (float) projection.length();
            Vector bigAxis = axisDirection.clone().scalarMultiple(5000.0);
            Vector subtraction = bigAxis.clone().subtract(projection);
            if (subtraction.length() > bigAxis.length()) {
                length *= -1;
            }

            length = proportionalScaling(length);
            float l = length;

            changeObject(currentTransformedObject, selectedAxis, l);
            angle *= -1;
            utils.setModified();
            lastLength = length;
            //System.out.println("Length = " + length /*+ "  dx=" + dx + "; dy=" + dy*/);

        } else if (gizmo_position != null) {
            selectedAxis = getIntersectedAxis(x, y);
        }

        processSelection(x, y, dx, dy, modifier);
        //super.mouseMove(x, y, dx, dy, modifier);
    }

    public void testRotateInLocalSpace(ISceneNode node, float degs, vector3df axis) {
        quaternion q = new quaternion();
        q.fromAngleAxis(degs * (float) (1 / 180.0 * Math.PI), axis);

        quaternion q0 = new quaternion();
        q0.set(node.getRotation().timesOperator((float) (1 / 180.0 * Math.PI)));

        q = q.timesOperator(q0);
        q.normalize();
        node.setRotation(q.toEulerDegrees());
    }

    @Override
    protected char getIntersectedAxis(int mouseX, int mouseY) {
        if (xdrawer == null || ydrawer == null || zdrawer == null) {
            return ' ';
        }
        vector3df cameraPosition = manager3D.getCamera().getRealCamera().getAbsolutePosition();
        ISceneCollisionManager cm = manager3D.getSceneManager().getSceneCollisionManager();
        CircleCollider collider = new CircleCollider(xdrawer);
        if (collider.isCollidedFrontPart(cm, cameraPosition, mouseX, mouseY)) {
            axisX1 = collider.getVect1().getX();
            axisY1 = collider.getVect1().getY();
            axisX2 = collider.getVect2().getX();
            axisY2 = collider.getVect2().getY();
            return 'x';
        }

        collider = new CircleCollider(ydrawer);
        if (collider.isCollidedFrontPart(cm, cameraPosition, mouseX, mouseY)) {
            axisX1 = collider.getVect1().getX();
            axisY1 = collider.getVect1().getY();
            axisX2 = collider.getVect2().getX();
            axisY2 = collider.getVect2().getY();
            return 'y';
        }

        collider = new CircleCollider(zdrawer);
        if (collider.isCollidedFrontPart(cm, cameraPosition, mouseX, mouseY)) {
            axisX1 = collider.getVect1().getX();
            axisY1 = collider.getVect1().getY();
            axisX2 = collider.getVect2().getX();
            axisY2 = collider.getVect2().getY();
            return 'z';
        }

        return ' ';
    }

    @Override
    protected void getNodeStateBeforeChangeState(ISceneNode node) {
        axisDirection = new Vector(axisX2 - axisX1, axisY2 - axisY1);
    }

    @Override
    protected float proportionalScaling(float length) {
        return -length;
    }

    @Override
    protected void onEndTransformation(ISceneNode node) {
        lastLength = 0;
        super.onEndTransformation(node);
    }
}
